﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;

namespace Assist
{
	public class GeoUtil
	{
		public static bool IsEqual(double d1, double d2)
		{
			return Math.Abs(d1 - d2) < 1E-05;
		}

		public static bool IsEqual(double d1, double d2, double dPrecision)
		{
			return Math.Abs(d1 - d2) < dPrecision;
		}

		public static bool IsPointEqual(XYZ pt1, XYZ pt2)
		{
			return Math.Abs(pt1.X - pt2.X) < 1E-05 && Math.Abs(pt1.Y - pt2.Y) < 1E-05 && Math.Abs(pt1.Z - pt2.Z) < 1E-05;
		}

		public static bool IsParallel(XYZ firstVec, XYZ secondVec)
		{
			return GeoUtil.IsSameDirection(firstVec, secondVec) || GeoUtil.IsOppositeDirection(firstVec, secondVec);
		}

		public static bool IsSameDirection(XYZ firstVec, XYZ secondVec)
		{
			XYZ xyz = firstVec.Normalize();
			XYZ xyz2 = secondVec.Normalize();
			return GeoUtil.IsEqual(xyz.DotProduct(xyz2), 1.0);
		}

		public static bool IsOppositeDirection(XYZ firstVec, XYZ secondVec)
		{
			XYZ xyz = firstVec.Normalize();
			XYZ xyz2 = secondVec.Normalize();
			return GeoUtil.IsEqual(xyz.DotProduct(xyz2), -1.0);
		}

		public static int GetPointQuadrant(XYZ ptStart, XYZ ptEnd, XYZ ptTest)
		{
			XYZ xyz = (ptEnd - ptStart).Normalize();
			XYZ xyz2 = RevitVersionFuncs.CreateRotationAtPoint(-XYZ.BasisZ, Math.PI*.5, ptStart).OfVector(xyz);
			XYZ xyz3 = (ptStart + ptEnd) / 2.0;
			XYZ xyz4 = (ptTest - xyz3).Normalize();
			double num = xyz4.DotProduct(xyz2);
			double num2 = xyz4.DotProduct(xyz);
			if (num > -1E-05 && num2 > 0.0)
			{
				return 1;
			}
			if (num < 0.0 && num2 > -1E-05)
			{
				return 2;
			}
			if (num < 1E-05 && num2 < 0.0)
			{
				return 3;
			}
			if (num > 0.0 && num2 < 1E-05)
			{
				return 4;
			}
			return 0;
		}

		public static void CompressPtsByDirect(UIApplication uiApp, List<XYZ> arPts)
		{
			if (arPts.Count <= 2)
			{
				return;
			}
			arPts.First<XYZ>();
			arPts.Last<XYZ>();
			List<XYZ> list = new List<XYZ>();
			while (arPts.Count > 1)
			{
				List<XYZ> list2 = new List<XYZ>();
				Line curve = uiApp.Application.CreatYJKLine(arPts.ElementAt(0), arPts.ElementAt(1), true);
				list2.Add(arPts.ElementAt(0));
				list2.Add(arPts.ElementAt(1));
				for (int i = 2; i < arPts.Count; i++)
				{
					XYZ xyz = arPts.ElementAt(i);
					if (CurveAssistFunc.GetClosestPointTo(uiApp, curve, xyz, true).DistanceTo(xyz) < 1E-05)
					{
						list2.Add(xyz);
					}
				}
				double num = 100000.0;
				double num2 = 0.0;
				XYZ item = null;
				XYZ item2 = null;
				XYZ xyz2 = list2.First<XYZ>() - (list2.Last<XYZ>() - list2.First<XYZ>()).Normalize() * 10000.0;
				for (int j = 0; j < list2.Count; j++)
				{
					double num3 = list2.ElementAt(j).DistanceTo(xyz2);
					if (num3 < num)
					{
						num = num3;
						item = list2.ElementAt(j);
					}
					if (num3 > num2)
					{
						num2 = num3;
						item2 = list2.ElementAt(j);
					}
					arPts.Remove(list2.ElementAt(j));
				}
				list.Add(item);
				list.Add(item2);
			}
			arPts.Clear();
			arPts.AddRange(list);
		}

		public static void SortPointByDirect(UIApplication uiApp, List<XYZ> arPts, XYZ vtDir)
		{
			if (arPts.Count < 2)
			{
				return;
			}
			XYZ xyz = arPts.First<XYZ>() - vtDir;
			XYZ endOrDirection = arPts.First<XYZ>() + vtDir;
			Line curve = uiApp.Application.CreatYJKLine(xyz, endOrDirection, true);
			List<PointSort> list = new List<PointSort>();
			for (int i = 0; i < arPts.Count; i++)
			{
				PointSort pointSort = new PointSort();
				pointSort.pt = arPts.ElementAt(i);
				XYZ closestPointTo = CurveAssistFunc.GetClosestPointTo(uiApp, curve, arPts.ElementAt(i), true);
				pointSort.param = closestPointTo.DistanceTo(xyz);
				list.Add(pointSort);
			}
			PointComparer comparer = new PointComparer();
			list.Sort(comparer);
			arPts.Clear();
			for (int j = 0; j < list.Count; j++)
			{
				arPts.Add(list.ElementAt(j).pt);
			}
		}

		public static void SortPointByCircle(UIApplication uiApp, List<XYZ> arPts, XYZ ptCenter)
		{
			if (arPts.Count <= 2)
			{
				return;
			}
			List<PointSort> list = new List<PointSort>();
			for (int i = 0; i < arPts.Count; i++)
			{
				PointSort pointSort = new PointSort();
				pointSort.pt = arPts.ElementAt(i);
				XYZ xyz = pointSort.pt - ptCenter;
				pointSort.param = xyz.AngleOnPlaneTo(XYZ.BasisX, -XYZ.BasisZ);
				list.Add(pointSort);
			}
			PointComparer comparer = new PointComparer();
			list.Sort(comparer);
			arPts.Clear();
			for (int j = 0; j < list.Count; j++)
			{
				arPts.Add(list.ElementAt(j).pt);
			}
		}

		public static void SortPointByArc(UIApplication uiApp, List<XYZ> arPts, Arc arc)
		{
			if (arPts.Count <= 2)
			{
				return;
			}
			XYZ center = arc.Center;
			XYZ xyz = arc.GetEndPoint(0) - center;
			XYZ xyz2 = arc.GetEndPoint(1) - center;
			XYZ xyz3 = ArcAssistFunc.IsClockwise(arc) ? xyz2 : xyz;
			List<PointSort> list = new List<PointSort>();
			for (int i = 0; i < arPts.Count; i++)
			{
				PointSort pointSort = new PointSort();
				pointSort.pt = arPts.ElementAt(i);
				XYZ xyz4 = pointSort.pt - center;
				pointSort.param = xyz4.AngleOnPlaneTo(xyz3, -XYZ.BasisZ);
				if (Math.Abs(pointSort.param - Math.PI*2) < 1E-05 && ArcAssistFunc.IsClockwise(arc))
				{
					pointSort.param = 0.0;
				}
				list.Add(pointSort);
			}
			PointComparer comparer = new PointComparer();
			list.Sort(comparer);
			arPts.Clear();
			for (int j = 0; j < list.Count; j++)
			{
				arPts.Add(list.ElementAt(j).pt);
			}
		}

		public static void GetPolyBoundPts(List<XYZ> arPts, ref XYZ ptMin, ref XYZ ptMax)
		{
			double num = 0.0;
			double num2 = 0.0;
			double num3 = 0.0;
			double num4 = 0.0;
			for (int i = 0; i < arPts.Count; i++)
			{
				XYZ xyz = arPts.ElementAt(i);
				if (i == 0)
				{
					num = xyz.X;
					num2 = xyz.Y;
					num3 = xyz.X;
					num4 = xyz.Y;
				}
				else
				{
					if (xyz.X < num)
					{
						num = xyz.X;
					}
					if (xyz.Y < num2)
					{
						num2 = xyz.Y;
					}
					if (xyz.X > num3)
					{
						num3 = xyz.X;
					}
					if (xyz.Y > num4)
					{
						num4 = xyz.Y;
					}
				}
			}
			ptMin = new XYZ(num, num2, ptMin.Z);
			ptMax = new XYZ(num3, num4, ptMax.Z);
		}

		private static double multiply(XYZ p1, XYZ p2, XYZ p0)
		{
			return (p1.X - p0.X) * (p2.Y - p0.Y) - (p2.X - p0.X) * (p1.Y - p0.Y);
		}

		public static void GrahamScan(List<XYZ> arPts)
		{
			int index = 0;
			int count = arPts.Count;
			for (int i = 1; i < count; i++)
			{
				if (arPts[i].Y < arPts[index].Y || (arPts[i].Y == arPts[index].Y && arPts[i].X < arPts[index].X))
				{
					index = i;
				}
			}
			XYZ value = arPts[0];
			arPts[0] = arPts[index];
			arPts[index] = value;
			for (int i = 1; i < count - 1; i++)
			{
				index = i;
				for (int j = i + 1; j < count; j++)
				{
					if (GeoUtil.multiply(arPts[j], arPts[index], arPts[0]) > 0.0 || (GeoUtil.multiply(arPts[j], arPts[index], arPts[0]) == 0.0 && arPts[0].DistanceTo(arPts[j]) < arPts[0].DistanceTo(arPts[index])))
					{
						index = j;
					}
				}
				value = arPts[i];
				arPts[i] = arPts[index];
				arPts[index] = value;
			}
		}

		public static int polyCentriod(List<XYZ> p, ref XYZ Center, ref double area, ref double length)
		{
			double num = 0.0;
			double num2 = 0.0;
			double num3 = 0.0;
			double num4 = 0.0;
			int count = p.Count;
			if (count < 3)
			{
				return 1;
			}
			int index = count - 1;
			for (int i = 0; i < count; i++)
			{
				double num5 = p[index].X * p[i].Y - p[i].X * p[index].Y;
				num += num5;
				num2 += (p[i].X + p[index].X) * num5;
				num3 += (p[i].Y + p[index].Y) * num5;
				num4 += Math.Sqrt((p[i].X - p[index].X) * (p[i].X - p[index].X) + (p[i].Y - p[index].Y) * (p[i].Y - p[index].Y));
				index = i;
			}
			area = num / 2.0;
			if (num != 0.0)
			{
				double num6 = (Center == null) ? 0.0 : Center.Z;
				XYZ xyz = new XYZ((double)((int)(num2 / (3.0 * num))), (double)((int)(num3 / (3.0 * num))), num6);
				Center = xyz;
				length = num4;
				if (area < 0.0)
				{
					area = -area;
				}
				return 0;
			}
			return 2;
		}

		public static List<LinkCurve> GetAllLinkCurve(UIApplication uiApp)
		{
			Document document = uiApp.ActiveUIDocument.Document;
			List<LinkCurve> list = new List<LinkCurve>();
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(document).OfCategory(BuiltInCategory.OST_Lines).OfClass(typeof(CurveElement));
			foreach (ElementId elementId in filteredElementCollector.ToElementIds())
			{
				ModelCurve modelCurve = document.GetElement(elementId) as ModelCurve;
				if (modelCurve != null)
				{
					foreach (ElementId elementId2 in filteredElementCollector.ToElementIds())
					{
						if (elementId != elementId2)
						{
							ModelCurve modelCurve2 = document.GetElement(elementId2) as ModelCurve;
							if (modelCurve2 != null)
							{
								IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
								modelCurve.GeometryCurve.Intersect(modelCurve2.GeometryCurve, out intersectionResultArray);
								if (intersectionResultArray != null)
								{
									IEnumerator enumerator3 = intersectionResultArray.GetEnumerator();
									{
										if (enumerator3.MoveNext())
										{
											IntersectionResult intersectionResult = (IntersectionResult)enumerator3.Current;
											XYZ hyendPoint = modelCurve.GeometryCurve.GetEndPoint(0);
											XYZ hyendPoint2 = modelCurve.GeometryCurve.GetEndPoint(1);
											if (intersectionResult.XYZPoint.IsAlmostEqualTo(hyendPoint) || intersectionResult.XYZPoint.IsAlmostEqualTo(hyendPoint2))
											{
												bool flag = true;
												foreach (LinkCurve linkCurve in list)
												{
													if (linkCurve.IsContains(uiApp, modelCurve.GeometryCurve))
													{
														flag = false;
														if (!linkCurve.IsContains(uiApp, modelCurve2.GeometryCurve))
														{
															linkCurve.Add(modelCurve2.GeometryCurve);
															break;
														}
													}
												}
												if (flag)
												{
													LinkCurve linkCurve2 = new LinkCurve();
													linkCurve2.Add(modelCurve.GeometryCurve);
													linkCurve2.Add(modelCurve2.GeometryCurve);
													list.Add(linkCurve2);
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
			return list;
		}

		public static LinkCurve GetLinkCurve(UIApplication uiApp)
		{
			Document document = uiApp.ActiveUIDocument.Document;
			LinkCurve linkCurve = new LinkCurve();
			ModelOrDetailCurveFilter modelOrDetailCurveFilter = new ModelOrDetailCurveFilter();
			List<Reference> list = null;
			try
			{
				list = uiApp.ActiveUIDocument.Selection.PickObjects(Autodesk.Revit.UI.Selection.ObjectType.Element, modelOrDetailCurveFilter, "请选择模型线或详图线作为沿线").ToList<Reference>();
			}
			catch
			{
				string text = "没有选择阵列沿线。";
				MessageBox.Show(text);
				throw new Exception(text);
			}
			LinkCurve result;
			try
			{
				if (document.GetElement(list[0]) is ModelCurve)
				{
					ModelCurve modelCurve = document.GetElement(list[0].ElementId) as ModelCurve;
					linkCurve.Add(modelCurve.GeometryCurve);
					using (List<Reference>.Enumerator enumerator = list.GetEnumerator())
					{
						while (enumerator.MoveNext())
						{
							Reference reference = enumerator.Current;
							if (document.GetElement(reference) is ModelCurve)
							{
								ModelCurve modelCurve2 = document.GetElement(reference) as ModelCurve;
								foreach (Reference reference2 in list)
								{
									if (reference != reference2)
									{
										ModelCurve modelCurve3 = document.GetElement(reference2) as ModelCurve;
										if (modelCurve3 != null)
										{
											IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
											modelCurve2.GeometryCurve.Intersect(modelCurve3.GeometryCurve, out intersectionResultArray);
											if (intersectionResultArray != null)
											{
												foreach (object obj in intersectionResultArray)
												{
													IntersectionResult intersectionResult = (IntersectionResult)obj;
													try
													{
														XYZ hyendPoint = modelCurve2.GeometryCurve.GetEndPoint(0);
														XYZ hyendPoint2 = modelCurve2.GeometryCurve.GetEndPoint(1);
														if ((intersectionResult.XYZPoint.IsAlmostEqualTo(hyendPoint) || intersectionResult.XYZPoint.IsAlmostEqualTo(hyendPoint2)) && linkCurve.IsContains(uiApp, modelCurve2.GeometryCurve) && !linkCurve.IsContains(uiApp, modelCurve3.GeometryCurve))
														{
															linkCurve.Add(modelCurve3.GeometryCurve);
														}
														break;
													}
													catch
													{
														break;
													}
												}
											}
										}
									}
								}
							}
						}
						goto IL_3AD;
					}
				}
				if (document.GetElement(list[0]) is DetailCurve)
				{
					DetailCurve detailCurve = document.GetElement(list[0]) as DetailCurve;
					linkCurve.Add(detailCurve.GeometryCurve);
					foreach (Reference reference3 in list)
					{
						if (document.GetElement(reference3) is DetailCurve)
						{
							DetailCurve detailCurve2 = document.GetElement(reference3) as DetailCurve;
							foreach (Reference reference4 in list)
							{
								if (reference3 != reference4)
								{
									DetailCurve detailCurve3 = document.GetElement(reference4) as DetailCurve;
									if (detailCurve3 != null)
									{
										IntersectionResultArray intersectionResultArray2 = new IntersectionResultArray();
										detailCurve2.GeometryCurve.Intersect(detailCurve3.GeometryCurve, out intersectionResultArray2);
										if (intersectionResultArray2 != null)
										{
											foreach (object obj2 in intersectionResultArray2)
											{
												IntersectionResult intersectionResult2 = (IntersectionResult)obj2;
												try
												{
													XYZ hyendPoint3 = detailCurve2.GeometryCurve.GetEndPoint(0);
													XYZ hyendPoint4 = detailCurve2.GeometryCurve.GetEndPoint(1);
													if ((intersectionResult2.XYZPoint.IsAlmostEqualTo(hyendPoint3) || intersectionResult2.XYZPoint.IsAlmostEqualTo(hyendPoint4)) && linkCurve.IsContains(uiApp, detailCurve2.GeometryCurve) && !linkCurve.IsContains(uiApp, detailCurve3.GeometryCurve))
													{
														linkCurve.Add(detailCurve3.GeometryCurve);
													}
													break;
												}
												catch
												{
													break;
												}
											}
										}
									}
								}
							}
						}
					}
				}
				IL_3AD:
				if (linkCurve.Count < list.Count)
				{
					throw new Exception("选择的集合中存在多条链接线或分支，请重新选择。");
				}
				result = linkCurve;
			}
			catch (Exception)
			{
				string text2 = "选择的集合中存在多条链接线或分支，请重新选择。";
				MessageBox.Show(text2);
				throw new Exception(text2);
			}
			return result;
		}

		private const double precision = 1E-05;
	}
}
